package com.seari.shiro;


import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExpiredCredentialsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.pam.UnsupportedTokenException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.seari.bean.User;
import com.seari.bean.UserPrivilege;
import com.seari.bean.UserRole;
import com.seari.pojo.QueryUser;
import com.seari.service.UserService;
import com.seari.utils.JwtUtil;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;

/**
 * 基于JWT（ JSON WEB TOKEN）的认证域
 */
public class JwtRealm extends AuthorizingRealm
{

	private static final Logger LOG = LoggerFactory.getLogger(JwtRealm.class);

	public static final String AUTHORIZATION_CACHE = "AuthorizationCache";

	public static final String AUTHRANTICATION_CACHE = "AuthranticationCache";

	@Autowired
	private UserService userService;

	@Override
	public Class<?> getAuthenticationTokenClass()
	{
		return JwtToken.class;// 此Realm只支持JwtToken
	}

	/**
	 * 用户授权
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection)
	{
		LOG.info("start doGetAuthorizationInfo function(用户授权)");
		SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
		User user = (User) principalCollection.getPrimaryPrincipal();
		UserRole userRole = user.getUserRole();
		simpleAuthorizationInfo.addRole(userRole.getRoleName());
		for (UserPrivilege userPrivilege : userRole.getPrivileges())
		{
			simpleAuthorizationInfo.addStringPermission(userPrivilege.getPrivilegeName());
		}
		LOG.info("end doGetAuthorizationInfo function(用户授权)");
		return simpleAuthorizationInfo;
	}

	/**
	 * 用户认证
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
			throws AuthenticationException
	{
		LOG.info("start doGetAuthenticationInfo function(用户认证)");
		JwtToken jwtToken = (JwtToken) authenticationToken;
		String jwt = jwtToken.getJwt();
		Claims claims;
		try
		{
			claims = JwtUtil.parseJWT(jwt);
		} catch (ExpiredJwtException e)
		{
			throw new ExpiredCredentialsException("JWT 已过期:" + e.getMessage());
		} catch (UnsupportedJwtException e)
		{
			throw new UnknownAccountException("JWT 令牌无效:" + e.getMessage());
		} catch (MalformedJwtException e)
		{
			throw new IncorrectCredentialsException("JWT 令牌格式错误:" + e.getMessage());
		} catch (SignatureException e)
		{
			throw new UnsupportedTokenException("JWT 令牌签名无效:" + e.getMessage());
		} catch (IllegalArgumentException e)
		{
			throw new IncorrectCredentialsException("JWT 令牌参数异常:" + e.getMessage());
		} catch (Exception e)
		{
			throw new AuthenticationException();
		}
		QueryUser queryUser = new QueryUser();
		queryUser.setUserName(claims.getSubject());
		queryUser.setStationName(claims.get("stationName").toString());
		User user = userService.getUserByParams(queryUser).get(0);
		if (user == null)
		{
			throw new UnknownAccountException();
		} 
//		else if (StringUtils.isEmpty(userInfo.getStatus()) || userInfo.getStatus() == UserInfo.STATUS_0)
//		{
//			throw new LockedAccountException();
//		}
		SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, Boolean.TRUE, getName());
		LOG.info("end doGetAuthenticationInfo function(用户认证)");
		return authenticationInfo;
	}
}
